package ru.amse.jsynchro.net.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import ru.amse.jsynchro.logging.ILogger;
import ru.amse.jsynchro.net.Command;
import ru.amse.jsynchro.net.User;

public class UserServerThread extends ServerThread {
    private Map<String, Semaphore> usersToSemaphore;
    
    private static int myThreadNumber = 0;
    
    private String XMLFileName;
    private String userName;
    
    private ILogger logger;
    
    public UserServerThread(Socket socket, int threadNumber, 
            Map<String, Semaphore> usersToSemaphore, 
            String XMLFileName, ILogger logger) {
        super(socket, threadNumber, logger);
        this.usersToSemaphore = usersToSemaphore;
        this.XMLFileName = XMLFileName;
        this.logger = logger;
    }
    
    public void run() {
        try {
            logger.info("serverthread: " + myThreadNumber + "  in run");
            socketOut = socket.getOutputStream();
            
            socketIn = socket.getInputStream();
            oout = new ObjectOutputStream(socketOut);
            oin = new ObjectInputStream(socketIn);
            try {
                if ((myLocalRoot = authenticate(loadUsers(XMLFileName))) == null) {
                    logger.info("unknown user");
                    return;
                }
            } catch (Exception e) {
                throw new AssertionError("users file error");
            }
            logger.info("serverthread: " + myLocalRoot);
            
            boolean listen = true;
            while (listen) {
               Command command = (Command) oin.readObject(); 
               listen = handleClientCommand(command);
            }
        } catch (IOException e) {
            logger.exception(e);
        } catch (ClassNotFoundException e) {
            logger.exception(e);
        }
        logger.info("releasing");
        usersToSemaphore.get(userName).release();
    }
    
    private List<User> loadUsers(String XMLFileName) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sparser = spf.newSAXParser();
        final List<User> users = new ArrayList<User>(); 
        DefaultHandler dh = new DefaultHandler() {
            public void startElement (String uri, String localName,
                String qName, Attributes attributes) throws SAXException {
                if (qName.equals("user")) {
                    User user  = new User(attributes.getValue("name"), attributes.getValue("password"),
                            attributes.getValue("folder"));
                    users.add(user);
                }
            }
        };
        FileInputStream fis = new FileInputStream(XMLFileName);
        sparser.parse(fis, dh);
        return users;
    }
    
    private String authenticate(List<User> users) throws ClassNotFoundException, IOException {
        logger.info("authentication:");
        userName = (String) oin.readObject(); 
        logger.info(userName);
        String userPassword = (String) oin.readObject();
        logger.info(userPassword);
        for(User user: users) {
            if (user.getName().equals(userName) && user.getPassword().equals(userPassword)) {
                try {
                    usersToSemaphore.get(userName).acquire();
                } catch (InterruptedException e) {
                    logger.exception(e);
                    throw new AssertionError("interrupted");
                }
                oout.writeObject("1");
                File file = new File(user.getDirectory());
                return file.getAbsolutePath();
            }
        }
        oout.writeObject("0");
        return null;
    }
}
